// ----------------------------------------------------------
// This Source Code Form is subject to the terms of the
// Mozilla Public License, v.2.0. If a copy of the MPL
// was not distributed with this file, You can obtain one
// at http://mozilla.org/MPL/2.0/.
// ----------------------------------------------------------
// Codebase: https://github.com/ArKuznetsov/cpdb/
// ----------------------------------------------------------

#Использовать deflator

Перем ПодключениеКСУБД;            // - ПодключениеКСУБД    - объект подключения к СУБД
Перем ТекущийСервер;               // - Строка              - адрес сервера СУБД
Перем База;                        // - Строка              - адрес сервера СУБД
Перем НазначенияОбъектовБазы;      // - Структура           - соответствие назначений объектов
                                   //                         префиксам имен объектов БД
Перем ПодчиненныеОбъектыБазы;      // - Структура           - назначения табличных частей префиксам имен объектов БД
Перем ВыражениеПроверкиЧисла;      // - РегулярноеВыражение - регулярное выражение для проверки числа
Перем ВыражениеОднотипныхСимволов; // - РегулярноеВыражение - регулярное выражение для проверки числа
Перем Лог;                         // - Объект              - объект записи лога приложения

#Область ПрограммныйИнтерфейс

// Функция проверяет, что база является базой 1С:Предприятие
//
// Возвращаемое значение:
//   Булево    - Истина - база является базой 1С
//
Функция ЭтоБаза1С() Экспорт

	РаботаССУБД = Новый РаботаССУБД(ПодключениеКСУБД);

	Возврат РаботаССУБД.ТаблицаСуществует(База, "v8users");

КонецФункции // ЭтоБаза1С()

// Функция - возвращает версию формата конфигурации
//
// Возвращаемое значение:
//   Структура            - описание версии формата конфигурации
//     *Версия                      - Число     - номер версии формата конфигурации
//     *ТребуемаяВерсияПлатформы    - Строка    - минимальная версия платформы 1С
//
Функция ВерсияФорматаКонфигурации() Экспорт

	Лог.Отладка("Начало получения версии формата конфигурации 1С базы ""%1/%2""",
	            ТекущийСервер,
	            База);

	Попытка
		Результат = ПодключениеКСУБД.ВерсияФорматаКонфигурации1С(База);
	Исключение
		ТекстОшибки = ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
		ТекстОшибки = СтрШаблон("Ошибка получения версия формата конфигурации 1С базы ""%1/%2"":%3%4",
		                        ТекущийСервер,
		                        База,
		                        Символы.ПС,
		                        ТекстОшибки);
		ВызватьИсключение ТекстОшибки;
	КонецПопытки;

	Лог.Отладка("Получена версии формата конфигурации 1С базы ""%1/%2"": %3",
	            ТекущийСервер,
	            База,
	            Результат.Версия);

	Возврат Результат;

КонецФункции // ВерсияФорматаКонфигурации()

// Функция - возвращает описание конфигурации
//
// Возвращаемое значение:
//   Структура                                   - описание конфигурации
//     *Имя                             - Строка    - имя конфигурации
//     *Синоним                         - Строка    - синоним конфигурации
//     *Версия                          - Строка    - версия конфигурации
//     *РежимСовместимости              - Строка    - версия режима совместимости конфигурации
//     *КраткаяИнформация               - Строка    - краткая информация о конфигурации
//     *ПодробнаяИнформация             - Строка    - подробная информация о конфигурации
//     *Поставщик                       - Строка    - поставщик конфигурации
//     *АвторскиеПрава                  - Строка    - данные об авторских правах
//     *АдресИнформацииОПоставщике      - Строка    - адрес сайта с информацией о поставщике
//     *АдресИнформацииОКонфигурации    - Строка    - адрес сайта с информацией о конфигурации
//     *АдресКаталогаОбновлений         - Строка    - адрес сайта с каталогом обновлений
//
Функция ОписаниеКонфигурации() Экспорт

	ОписаниеКонфигурации = Новый Структура();
	ОписаниеКонфигурации.Вставить("Имя"                         , "");
	ОписаниеКонфигурации.Вставить("Синоним"                     , "");
	ОписаниеКонфигурации.Вставить("Версия"                      , "");
	ОписаниеКонфигурации.Вставить("РежимСовместимости"          , "");
	ОписаниеКонфигурации.Вставить("КраткаяИнформация"           , "");
	ОписаниеКонфигурации.Вставить("ПодробнаяИнформация"         , "");
	ОписаниеКонфигурации.Вставить("Поставщик"                   , "");
	ОписаниеКонфигурации.Вставить("АвторскиеПрава"              , "");
	ОписаниеКонфигурации.Вставить("АдресИнформацииОПоставщике"  , "");
	ОписаниеКонфигурации.Вставить("АдресИнформацииОКонфигурации", "");
	ОписаниеКонфигурации.Вставить("АдресКаталогаОбновлений"     , "");

	Лог.Отладка("Начало получения корневого файла конфигурации 1С базы ""%1/%2""",
	            ТекущийСервер,
	            База);

	Попытка
		Результат = ПодключениеКСУБД.ФайлКонфигурации1С(База, "root");
	Исключение
		ТекстОшибки = ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
		ТекстОшибки = СтрШаблон("Ошибка получения корневого файла конфигурации 1С базы ""%1/%2"":%3%4",
		                        ТекущийСервер,
		                        База,
		                        Символы.ПС,
		                        ТекстОшибки);
		ВызватьИсключение ТекстОшибки;
	КонецПопытки;

	Данные = ПрочитатьУпакованныеДанные(Результат, Истина);

	РВ = Новый РегулярноеВыражение("\{\d+,(?i)([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})," +
	                               "((?:.|\s)*)\}");

	Совпадения = РВ.НайтиСовпадения(Данные);

	Если Совпадения.Количество() = 0 Тогда
		Возврат Результат;
	КонецЕсли;

	ИдФайла = Совпадения[0].Группы[1].Значение;

	Лог.Отладка("Получен корневой файл конфигурации 1С базы ""%1/%2"": %3",
	            ТекущийСервер,
	            База,
	            ИдФайла);

	Лог.Отладка("Начало получения описания конфигурации 1С базы ""%1/%2""",
	            ТекущийСервер,
	            База);

	Попытка
		Результат = ПодключениеКСУБД.ФайлКонфигурации1С(База, ИдФайла);
	Исключение
		ТекстОшибки = ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
		ТекстОшибки = СтрШаблон("Ошибка получения описания конфигурации 1С базы ""%1/%2"":%3%4",
		                        ТекущийСервер,
		                        База,
		                        Символы.ПС,
		                        ТекстОшибки);
		ВызватьИсключение ТекстОшибки;
	КонецПопытки;

	Данные = ПрочитатьУпакованныеДанные(Результат, Истина);

	ЗаполнитьТекстыВОписанииКонфигурации(ОписаниеКонфигурации, Данные);
	ЗаполнитьВерсиюВОписанииКонфигурации(ОписаниеКонфигурации, Данные);

	Возврат ОписаниеКонфигурации;

КонецФункции // ОписаниеКонфигурации()

// Функция - возвращает описание метаданных 1С для объекта СУБД по его имени
//
// Параметры:
//   ИмяОбъекта          - Строка    - Имя таблицы или поля таблицы СУБД
//
// Возвращаемое значение:
//    Структура    - описание метаданных 1С по имени объекта СУБД (см. СтруктураОписанияОбъектаБазы())
//
Функция ОписаниеМетаданныхОбъектаБД1С(Знач ИмяОбъекта) Экспорт

	УбратьЛидирующееПодчеркивание(ИмяОбъекта);

	ОписаниеОбъектаБазы = ОписаниеОбъектаБазыПоИмени(ИмяОбъекта);

	ДобавлятьКолонки = Ложь;

	Если НазначениеОбъектаБазы(ОписаниеОбъектаБазы).Назначение = "Поле" Тогда
		КолонкиБазы = КолонкиБазы(, СтрШаблон("%%%1%%", ИмяОбъекта));
		Если КолонкиБазы.Количество() > 0 Тогда
			ОписаниеОбъектаБазы = КолонкиБазы[ИмяОбъекта];
		Иначе
			Возврат Неопределено;
		КонецЕсли;
		ДобавлятьКолонки = Истина;
	КонецЕсли;

	ИменаТаблицОбъектовКонфигурации1С = ИменаТаблицОбъектовКонфигурации1С(ДобавлятьКолонки);

	ОписаниеВладельца = ОписаниеОбъектаБазы;
	Пока ЗначениеЗаполнено(ОписаниеВладельца.Владелец) Цикл
		ОписаниеВладельца.Вставить("Ид", ИменаТаблицОбъектовКонфигурации1С[ОписаниеВладельца.Имя].Ид);
		ОписаниеВладельца = ОписаниеВладельца.Владелец;
	КонецЦикла;
	ОписаниеВладельца.Вставить("Ид", ИменаТаблицОбъектовКонфигурации1С[ОписаниеВладельца.Имя].Ид);

	СоответствиеИменМетаданных = СоответствиеИменМетаданных(ОписаниеВладельца.Ид);

	ОписаниеВладельца.Вставить("ИмяМетаданных", СоответствиеИменМетаданных[ОписаниеВладельца.Ид].ИмяМетаданных);

	ТекОписание = ОписаниеОбъектаБазы;
	Пока ЗначениеЗаполнено(ТекОписание.Владелец) Цикл
		ИмяМетаданных = ИмяМетаданных(СоответствиеИменМетаданных[ОписаниеВладельца.Ид].Данные, ТекОписание);
		ТекОписание.Вставить("ИмяМетаданных", ИмяМетаданных);
		ТекОписание = ТекОписание.Владелец;
	КонецЦикла;

	ЗаполнитьПолныеИменаМетаданныхВОписанииОбъектаБазы(ОписаниеОбъектаБазы);

	Возврат ОписаниеОбъектаБазы;

КонецФункции // ОписаниеМетаданныхОбъектаБД1С()

// Функция - возвращает описание метаданных 1С для таблиц и полей таблиц СУБД
//
// Параметры:
//   ДобавлятьКолонки    - Булево    - Истина - будет добавлена информация для колонок таблиц
//
// Возвращаемое значение:
//    Соответствие    - соответствия имен таблиц СУБД и полных имен метаданных 1С описаниям объектов метаданных 1С
//                      (см. СтруктураОписанияОбъектаБазы())
//
Функция ОписаниеМетаданныхОбъектовБД1С(ДобавлятьКолонки = Ложь) Экспорт

	ОписанияМетаданных = Новый Соответствие();

	ИменаТаблицОбъектовКонфигурации1С = ИменаТаблицОбъектовКонфигурации1С(ДобавлятьКолонки);

	СоответствиеИменМетаданных = СоответствиеИменМетаданных();

	КолонкиБазы = Новый Соответствие();
	Если ДобавлятьКолонки Тогда
		КолонкиБазы = КолонкиБазы();
	КонецЕсли;
	
	ТабличныеЧасти = ТабличныеЧастиИВладельцы();

	Для Каждого ТекЭлемент Из ИменаТаблицОбъектовКонфигурации1С Цикл

		ОписаниеОбъектаБазы = ОписаниеОбъектаБазыПоСоответствиюИмениОбъектаИИд(ТекЭлемент.Значение,
		                                                                       ТабличныеЧасти,
		                                                                       КолонкиБазы);

		ОписаниеВладельца = ЗаполнитьОписаниеОбъектаБазыИВладельцев(ОписаниеОбъектаБазы,
		                                                            ОписанияМетаданных,
		                                                            ИменаТаблицОбъектовКонфигурации1С,
		                                                            СоответствиеИменМетаданных);

		Если ЗначениеЗаполнено(ОписаниеВладельца) Тогда
			ОписанияМетаданных.Вставить(ОписаниеВладельца.ПолноеИмяМетаданных, ОписаниеВладельца);
		КонецЕсли;

		ТекОписание = ОписаниеОбъектаБазы;
		Пока ЗначениеЗаполнено(ТекОписание.Владелец) Цикл
			ОписанияМетаданных.Вставить(ТекОписание.ПолноеИмяМетаданных, ТекОписание);
			ТекОписание = ТекОписание.Владелец;
		КонецЦикла;

	КонецЦикла;

	Возврат ОписанияМетаданных;

КонецФункции // ОписаниеМетаданныхОбъектовБД1С()

// Функция - возвращает описание занимаеиого места в базе MS SQL Server
//
// Возвращаемое значение:
//  Структура                      - описание занимаего места
//    * РазмерБазы         - Число    - размер текущей базы данных в байтах, включает файлы данных и журналов
//    * Свободно           - Число    - место в базе данных, не зарезервированное для объектов базы данных
//    * Зарезервировано    - Число    - общий объем, выделенный объектам в базе данных
//     *Данные             - Число    - зарезервированный объем, используемый данными
//     *Индексы            - Число    - зарезервированный объем, используемый индексами
//     *НеИспользуется     - Число    - объем, зарезервированный для объектов в базе данных,
//                                      но пока не используемый
//     *ЖурналВсего        - Число    - полный объем журнала транзакций
//     *ЖурналИспользуется - Число    - используемый объем журнала транзакций
//
Функция ЗанимаемоеМесто() Экспорт

	Результат = Новый Структура();
	Результат.Вставить("РазмерБазы");
	Результат.Вставить("Свободно");
	Результат.Вставить("Зарезервировано");
	Результат.Вставить("Данные");
	Результат.Вставить("Индексы");
	Результат.Вставить("НеИспользуется");
	Результат.Вставить("ЖурналВсего");
	Результат.Вставить("ЖурналИспользуется");

	Лог.Отладка("Начало получения информации о занимаемом месте для базы ""%1/%2""",
	            ТекущийСервер,
	            База);

	Попытка
		Результат = ПодключениеКСУБД.ЗанимаемоеБазойМесто(База);
		КоличествоТаблиц = ПодключениеКСУБД.ТаблицыБазы(База, Истина);
	Исключение
		ТекстОшибки = ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
		ТекстОшибки = СтрШаблон("Ошибка получения информации о занимаемом месте для базы ""%1/%2"":%3%4",
		                        ТекущийСервер,
		                        База,
		                        Символы.ПС,
		                        ТекстОшибки);
		ВызватьИсключение ТекстОшибки;
	КонецПопытки;

	Лог.Отладка("Получена информация о занимаемом месте для базы ""%1/%2""", ТекущийСервер, База);

	Для Каждого ТекЭлемент Из Результат Цикл

		Если ЭтоЧисло(ТекЭлемент.Значение) Тогда
			Результат[ТекЭлемент.Ключ] = Число(ТекЭлемент.Значение);
		Иначе
			Результат[ТекЭлемент.Ключ] = Неопределено;
		КонецЕсли;
	КонецЦикла;

	Результат.Вставить("КоличествоТаблиц", КоличествоТаблиц);

	Возврат Результат;

КонецФункции // ЗанимаемоеМесто()

// Функция - возвращает список таблиц в базе MS SQL Server и их показатели использования
//
// Параметры:
//   ФильтрТаблицПоИмени    - Строка    - фильтр имен таблиц в формате для оператора "LIKE"
//   СтатистикаОпераций     - Булево    - Истина - в результат будет включена статистика по операциям с таблицами
//                                        (для больших баз - может занять много времени)
//
// Возвращаемое значение:
//  Массив из Структура                   - таблицы и показатели использования
//     *Таблица                 - Строка    - имя таблицы
//     *КоличествоСтрок         - Число     - количество строк в таблице
//     *ВсегоЗанято             - Число     - общий объем заниаемого места (байт)
//     *Используется            - Число     - объем, используемый данными (байт)
//     *НеИспользуется          - Число     - не используемый объем (байт)
//     *ОперацийЧтения          - Число     - количество операций чтения (read)
//     *ОперацийВыборки         - Число     - количество операций выборки (select)
//     *ОперацийСканирования    - Число     - количество операций сканирования (scan)
//     *ОперацийПоиска          - Число     - количество операций поиска (seek)
//     *ОперацийЗаписи          - Число     - количество операций записи (write)
//
Функция ПоказателиИспользованияТаблицБазы(ФильтрТаблицПоИмени = "", СтатистикаОпераций = Ложь) Экспорт

	Лог.Отладка("Начало получения информации о показателях использования таблиц для базы ""%1/%2""",
	            ТекущийСервер,
	            База);

	Попытка
		ПоказателиТаблиц = ПодключениеКСУБД.ПоказателиИспользованияТаблицБазы(База, ФильтрТаблицПоИмени, СтатистикаОпераций);
	Исключение
		ТекстОшибки = ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
		ТекстОшибки = СтрШаблон("Ошибка получения информации о показателях использования таблиц
		                        | для базы ""%1/%2"":%3%4",
		                        ТекущийСервер,
		                        База,
		                        Символы.ПС,
		                        ТекстОшибки);
		ВызватьИсключение ТекстОшибки;
	КонецПопытки;

	Лог.Отладка("Получена информация о показателях использования таблиц для базы ""%1/%2""", ТекущийСервер, База);

	Для Каждого ТекТаблица Из ПоказателиТаблиц Цикл

		Для Каждого ТекПоказатель Из ТекТаблица Цикл

			Если ВРег(ТекПоказатель.Ключ) = "ТАБЛИЦА" Тогда
				Продолжить;
			КонецЕсли;

			Если ЭтоЧисло(ТекПоказатель.Значение) Тогда
				ТекТаблица[ТекПоказатель.Ключ] = Число(ТекПоказатель.Значение);
			Иначе
				ТекТаблица[ТекПоказатель.Ключ] = Неопределено;
			КонецЕсли;
		КонецЦикла;

	КонецЦикла;

	Возврат ПоказателиТаблиц;

КонецФункции // ПоказателиИспользованияТаблицБазы()

#КонецОбласти // ПрограммныйИнтерфейс

#Область СлужебныеПроцедурыИФункции

// Функция - читает соответствия UUID объектов метаданных конфигурации 1С именам объектов базы
// из таблицы Params из записи где "[FileName] = 'DBNames'"
//
// Параметры:
//   ДобавлятьКолонки    - Строка    - Истина - будет добавлена информация для колонок таблиц
//
// Возвращаемое значение:
//    Соответствие    - соответствия UUID объектов метаданных конфигурации 1С именам объектов СУБД
//
Функция ИменаТаблицОбъектовКонфигурации1С(ДобавлятьКолонки = Ложь)

	Лог.Отладка("Начало получения соответствия UUID объектов метаданных конфигурации 1С
	            | именам объектов базы ""%1/%2""",
	            ТекущийСервер,
	            База);

	Попытка
		Данные = ПодключениеКСУБД.ИменаТаблицОбъектовКонфигурации1С(База);
	Исключение
		ТекстОшибки = ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
		ТекстОшибки = СтрШаблон("Ошибка получения соответствия UUID объектов метаданных конфигурации 1С
		                        | именам объектов базы ""%1/%2"":%3%4",
		                        ТекущийСервер,
		                        База,
		                        Символы.ПС,
		                        ТекстОшибки);
		ВызватьИсключение ТекстОшибки;
	КонецПопытки;

	Данные = ПрочитатьУпакованныеДанные(Данные);

	Чтение = Новый ЧтениеТекста(Данные.ОткрытьПотокДляЧтения(), КодировкаТекста.UTF8, Символы.ПС, Символы.ПС + Символы.ВК);

	ИменаТаблицОбъектовКонфигурации1С = Новый Соответствие();

	КоличествоПолей = 3;

	ТекСтрока = Чтение.ПрочитатьСтроку();

	Пока НЕ ТекСтрока = Неопределено Цикл

		ТекСтрока = СтрЗаменить(ТекСтрока, "{", "");
		ТекСтрока = СтрЗаменить(ТекСтрока, "}", "");

		ЧастиСтроки = СтрРазделить(ТекСтрока, ",", Ложь);

		Если ЧастиСтроки.Количество() < КоличествоПолей Тогда
			ТекСтрока = Чтение.ПрочитатьСтроку();
			Продолжить;
		КонецЕсли;

		ИндексСтрокой = ЧастиСтроки[2];

		СтрокаСоответствия = Новый Структура();
		СтрокаСоответствия.Вставить("Ид"     , ПривестиСтроку(ЧастиСтроки[0]));
		СтрокаСоответствия.Вставить("Префикс", ПривестиСтроку(ЧастиСтроки[1]));
		СтрокаСоответствия.Вставить("Индекс" , ПривестиСтроку(ИндексСтрокой));
		СтрокаСоответствия.Вставить("Суффикс", "");

		Если НЕ ДобавлятьКолонки И НазначениеОбъектаБазы(СтрокаСоответствия).Назначение = "Поле" Тогда
			ТекСтрока = Чтение.ПрочитатьСтроку();
			Продолжить;
		КонецЕсли;

		ИмяОбъекта = СтрШаблон("%1%2", СтрокаСоответствия.Префикс, ИндексСтрокой);
		ИменаТаблицОбъектовКонфигурации1С.Вставить(ИмяОбъекта, СтрокаСоответствия);

		ТекСтрока = Чтение.ПрочитатьСтроку();
	КонецЦикла;

	Возврат ИменаТаблицОбъектовКонфигурации1С;

КонецФункции // ИменаТаблицОбъектовКонфигурации1С()

// Функция - читает таблицу Config базы 1С и возвращает соответствия UUID метаданных и имен метаданных
//
// Параметры:
//   Ид              - Число      - идентификатор объекта метаданных,
//                                  если не указан, считываются все записи
//   ПорцияЧтения    - Число      - количество строк таблицы Config читаемое за 1 запрос
//
// Возвращаемое значение:
//   Соответствие    - соответствия UUID метаданных и имен метаданных
//
Функция СоответствиеИменМетаданных(Ид = "", ПорцияЧтения = 5000)

	Лог.Отладка("Получение соответствия имен метаданных базы ""%1/%2"": %3",
	            ТекущийСервер,
	            База);

	СоответствиеИменМетаданных = Новый Соответствие();

	ВсегоЗаписей = ПодключениеКСУБД.КоличествоОбъектовКонфигурацииБазы1С(База, Ид);
	Прочитано = 0;
	
	Пока Прочитано < ВсегоЗаписей Цикл
	
		Попытка
			ОбъектыКонфигурации = ПодключениеКСУБД.ОбъектыКонфигурацииБазы1С(База, Ид, Прочитано, ПорцияЧтения);
		Исключение
			ТекстОшибки = ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
			ТекстОшибки = СтрШаблон("Ошибка получения соответствия имен метаданных базы ""%1/%2"":%3%4",
			                        ТекущийСервер,
			                        База,
			                        Символы.ПС,
			                        ТекстОшибки);
			ВызватьИсключение ТекстОшибки;
		КонецПопытки;
	
		Для Каждого ТекЭлемент Из ОбъектыКонфигурации Цикл
			Данные = ПрочитатьУпакованныеДанные(ТекЭлемент.Значение.Данные, Истина);
			ТекЭлемент.Значение.Вставить("Данные", Данные);
			ТекЭлемент.Значение.Вставить("ИмяМетаданных", ИмяМетаданных(Данные, ТекЭлемент.Значение.Ид));
			СоответствиеИменМетаданных.Вставить(ТекЭлемент.Ключ, ТекЭлемент.Значение);
		КонецЦикла;

		Прочитано = Прочитано + ПорцияЧтения;
	
	КонецЦикла;
	
	Возврат СоответствиеИменМетаданных;

КонецФункции // СоответствиеИменМетаданных()

// Процедура - заполняет соответствие имен объектов базы данных Типам и именам объектов 1С
// в переменной модуля "НазначенияОбъектовБазы"
// и назначения табличных частей в переменной модуля "ПодчиненныеОбъектыБазы"
//
Процедура ЗаполнитьНазначенияОбъектовБазы()

	ИмяМакета = "НазначенияОбъектовБД1С.json";
	ПутьКМакету = ОбъединитьПути(ТекущийСценарий().Каталог, "..", "Макеты", ИмяМакета);
	ФайлМакета = Новый Файл(ПутьКМакету);

	Чтение = Новый ЧтениеJSON();
	Чтение.ОткрытьФайл(ФайлМакета.ПолноеИмя, КодировкаТекста.UTF8);

	НазначенияОбъектовБазы = ПрочитатьJSON(Чтение, Ложь);
	ПодчиненныеОбъектыБазы = Новый Структура();

	Для Каждого ТекЭлемент Из НазначенияОбъектовБазы Цикл
		Если НЕ ТекЭлемент.Значение.Свойство("Подчиненный") Тогда
			ТекЭлемент.Значение.Вставить("Подчиненный", Ложь);
		ИначеЕсли ТекЭлемент.Значение.Подчиненный Тогда
			ПодчиненныеОбъектыБазы.Вставить(ТекЭлемент.Ключ, ТекЭлемент.Значение);
		КонецЕсли;
	КонецЦикла;

КонецПроцедуры // ЗаполнитьНазначенияОбъектовБазы()

// Функция - возвращает описание назначения объекта базы
//
// Параметры:
//   ОписаниеОбъектаБазы    - Структура    - описание объекта базы
//
// Возвращаемое значение:
//   Структура    - назначения объектов базы
//
Функция НазначениеОбъектаБазы(ОписаниеОбъектаБазы)

	Если НЕ ТипЗнч(НазначенияОбъектовБазы) = Тип("Структура") Тогда
		ЗаполнитьНазначенияОбъектовБазы();
	КонецЕсли;

	ОписаниеНазначения = Новый Структура();

	Для Каждого ТекЭлемент Из НазначенияОбъектовБазы.Config Цикл
		ОписаниеНазначения.Вставить(ТекЭлемент.Ключ, "");
	КонецЦикла;

	Если НазначенияОбъектовБазы.Свойство(ОписаниеОбъектаБазы.Префикс) Тогда
		ЗаполнитьЗначенияСвойств(ОписаниеНазначения, НазначенияОбъектовБазы[ОписаниеОбъектаБазы.Префикс]);
	КонецЕсли;

	ЭтоСсылкаНаВладельцаТЧ = (ОписаниеОбъектаБазы.Свойство("Владелец")
	                        И ЗначениеЗаполнено(ОписаниеОбъектаБазы.Владелец)
	                        И ОписаниеОбъектаБазы.Владелец.Тип = "ТабличнаяЧасть"
	                        И ОписаниеОбъектаБазы.Суффикс = "_IDRRef");
	Если ЭтоСсылкаНаВладельцаТЧ Тогда
		ОписаниеНазначения.Тип = "Ссылка";
		ОписаниеНазначения.ТипАнгл = "Ref";
		ОписаниеНазначения.Назначение = "Поле";
	КонецЕсли;

	Возврат ОписаниеНазначения;

КонецФункции // НазначениеОбъектаБазы()

// Функция - возвращает список таблиц базы, соответствующих фильтру
//
// Параметры:
//   ТолькоКоличество       - Булево    - Истина - возвращать только количество таблиц базы
//   ФильтрТаблицПоИмени    - Строка    - фильтр имен таблиц в формате для оператора "LIKE"
//
// Возвращаемое значение:
//  Соответствие    - список таблиц базы
//
Функция ТаблицыБазы(ТолькоКоличество = Ложь, ФильтрТаблицПоИмени = "")

	Лог.Отладка("Получение таблиц базы ""%1/%2"": %3", ТекущийСервер, База);

	Попытка
		Таблицы = ПодключениеКСУБД.ТаблицыБазы(База, ТолькоКоличество, ФильтрТаблицПоИмени);
	Исключение
		ТекстОшибки = ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
		ТекстОшибки = СтрШаблон("Ошибка получения таблиц базы ""%1/%2"":%3%4",
		                        ТекущийСервер,
		                        База,
		                        Символы.ПС,
		                        ТекстОшибки);
		ВызватьИсключение ТекстОшибки;
	КонецПопытки;

	Лог.Отладка("Получены таблицы базы ""%1/%2""", ТекущийСервер, База);

	Результат = Новый Соответствие();

	Для Каждого ТекТаблица Из Таблицы Цикл
		УбратьЛидирующееПодчеркивание(ТекТаблица);
		Результат.Вставить(ТекТаблица, ТекТаблица);
	КонецЦикла;

	Возврат Результат;

КонецФункции // ТаблицыБазы()

// Функция - список таблиц, хранящих данные табличных частей объектов 1С
// с указанием таблиц объектов-владельцев
//
// Возвращаемое значение:
//  Соответствие    - список таблиц, хранящих данные табличных частей объектов 1С
//
Функция ТабличныеЧастиИВладельцы()

	ТабличныеЧастиИВладельцы = Новый Соответствие();

	Для Каждого ТекНазначение Из ПодчиненныеОбъектыБазы Цикл

		ТаблицыБазы = ТаблицыБазы(Ложь, СтрШаблон("%%_%1%%", ТекНазначение.Значение.Префикс));

		Для Каждого ТекТаблица Из ТаблицыБазы Цикл
			ОписаниеОбъектаБазы = ОписаниеОбъектаБазыПоИмени(ТекТаблица.Значение);

			ИмяОбъектаБазы = СтрШаблон("%1%2", ОписаниеОбъектаБазы.Префикс, ОписаниеОбъектаБазы.Индекс);
			ТабличныеЧастиИВладельцы.Вставить(ИмяОбъектаБазы, ОписаниеОбъектаБазы);
		КонецЦикла;

	КонецЦикла;

	Возврат ТабличныеЧастиИВладельцы;

КонецФункции // ТабличныеЧастиИВладельцы()

// Функция - возвращает список колонок базы, соответствующих фильтру
//
// Параметры:
//  ФильтрТаблицПоИмени      - Строка    - фильтр имен таблиц в формате для оператора "LIKE"
//  ФильтрКолонокПоИмени     - Строка    - фильтр имен колонок в формате для оператора "LIKE"
//
// Возвращаемое значение:
//  Соответствие    - список колонок базы
//
Функция КолонкиБазы(ФильтрТаблицПоИмени = "", ФильтрКолонокПоИмени = "")

	Лог.Отладка("Получение списка колонок базы ""%1/%2"": %3", ТекущийСервер, База);

	Попытка
		Колонки = ПодключениеКСУБД.КолонкиБазы(База, ФильтрТаблицПоИмени, ФильтрКолонокПоИмени);
	Исключение
		ТекстОшибки = ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
		ТекстОшибки = СтрШаблон("Ошибка получения списка колонок базы ""%1/%2"":%3%4",
		                        ТекущийСервер,
		                        База,
		                        Символы.ПС,
		                        ТекстОшибки);
		ВызватьИсключение ТекстОшибки;
	КонецПопытки;

	Лог.Отладка("Получен список колонок базы ""%1/%2""", ТекущийСервер, База);

	КэшВладельцев = Новый Соответствие();

	Результат = Новый Соответствие();

	Для Каждого ТекКолонка Из Колонки Цикл

		Если КэшВладельцев[ТекКолонка.Таблица] = Неопределено Тогда
			ОписаниеОбъектаВладельца = ОписаниеОбъектаБазыПоИмени(ТекКолонка.Таблица);
			КэшВладельцев.Вставить(ТекКолонка.Таблица, ОписаниеОбъектаВладельца);
		КонецЕсли;

		ОписаниеОбъектаКолонки = ОписаниеОбъектаБазыПоИмени(ТекКолонка.Колонка);
		ОписаниеОбъектаКолонки.Владелец = КэшВладельцев[ТекКолонка.Таблица];

		// Проверка, что поле является ссылкой из табличной части
		Если ЗначениеЗаполнено(ОписаниеОбъектаКолонки.Владелец.Владелец)
		   И ОписаниеОбъектаКолонки.Имя = ОписаниеОбъектаКолонки.Владелец.Владелец.Имя Тогда
			ОписаниеОбъектаКолонки.Тип = "Ссылка";
			ОписаниеОбъектаКолонки.ТипАнгл = "Ref";
			ОписаниеОбъектаКолонки.Назначение = "Поле";
		КонецЕсли;

		Результат.Вставить(ОписаниеОбъектаКолонки.Имя, ОписаниеОбъектаКолонки);

	КонецЦикла;

	Возврат Результат;

КонецФункции // КолонкиБазы()

// Функция - возвращает структуру описания объекта базы данных 1С
//
// Возвращаемое значение:
//  Структура                             - структура описания объекта базы
//    *Владелец               - Структура    - структура описания объекта владельца
//    *Тип                    - Строка       - тип объекта или коллекция
//                                             (например: Справочник, Документ, ТабличнаяЧасть, Поле)
//    *ТипАнгл                - Строка       - тип объекта или коллекция на английском
//                                             (например: Reference, Document, TabularSection, Field)
//    *Назначение             - Строка       - назначение таблицы БД (например: Основная, Итоги, Обороты)
//    *Имя                    - Строка       - имя объекта в БД (Префикс + Индекс)
//    *Префикс                - Строка       - префикс объекта (например: Reference, Document, VT, Fld))
//    *Индекс                 - Число        - числовой индекс объекта
//    *Суффикс                - Строка       - дополнительный суффикс имени объекта (например: "_RRef")
//    *Ид                     - Строка       - UUID объекта 1С
//    *ИмяМетаданных          - Строка       - имя метаданных 1С
//    *ПолноеИмяМетаданных    - Строка       - имя метаданных 1С
//
Функция СтруктураОписанияОбъектаБазы()

	СтруктураОписания = Новый Структура();
	СтруктураОписания.Вставить("Владелец");
	СтруктураОписания.Вставить("Тип"                , "");
	СтруктураОписания.Вставить("ТипАнгл"            , "");
	СтруктураОписания.Вставить("Назначение"         , "");
	СтруктураОписания.Вставить("Имя"                , "");
	СтруктураОписания.Вставить("Префикс"            , "");
	СтруктураОписания.Вставить("Индекс");
	СтруктураОписания.Вставить("Суффикс"            , "");
	СтруктураОписания.Вставить("Ид"                 , "");
	СтруктураОписания.Вставить("ИмяМетаданных"      , "");
	СтруктураОписания.Вставить("ПолноеИмяМетаданных", "");

	Возврат СтруктураОписания;

КонецФункции // СтруктураОписанияОбъектаБазы()

// Функция - раскладывает имя объекта базы на префикс, индекс, владельца и суффикс
//
// Параметры:
//  ИмяОбъектаБазы     - Строка    - имя объекта базы
// 
// Возвращаемое значение:
//  Структура    - имя объекта базы, префикс, индекс, владелец и суффикс (см. СтруктураОписанияОбъектаБазы())
//
Функция ОписаниеОбъектаБазыПоИмени(Знач ИмяОбъектаБазы)

	ОписаниеОбъектаБазы = СтруктураОписанияОбъектаБазы();

	УбратьЛидирующееПодчеркивание(ИмяОбъектаБазы);

	ПрефиксОбъекта = ПрочитатьОднотипныеСимволы(ИмяОбъектаБазы);
	ИмяОбъектаБазы = Сред(ИмяОбъектаБазы, СтрДлина(ПрефиксОбъекта) + 1);
	Символ = Сред(ИмяОбъектаБазы, 1, 1);

	ПозицияИмениТЧ = СтрНайти(ИмяОбъектаБазы, "_");
	Если ПозицияИмениТЧ > 0 Тогда
		ПрефиксИмениТЧ = ПрочитатьОднотипныеСимволы(Сред(ИмяОбъектаБазы, ПозицияИмениТЧ + 1));
		Если ПодчиненныеОбъектыБазы.Свойство(ПрефиксИмениТЧ) Тогда
			ПрефиксИмениТЧ = ПодчиненныеОбъектыБазы[ПрефиксИмениТЧ].Префикс;
		Иначе
			ПозицияИмениТЧ = 0;
			ПрефиксИмениТЧ = "";
		КонецЕсли;
	КонецЕсли;

	Если ПозицияИмениТЧ > 0 Тогда
		ОписаниеОбъектаБазы.Владелец =
			ОписаниеОбъектаБазыПоИмени(ПрефиксОбъекта + Лев(ИмяОбъектаБазы, ПозицияИмениТЧ - 1));
		ПрефиксОбъекта = ПрефиксИмениТЧ;
		ИмяОбъектаБазы = Сред(ИмяОбъектаБазы, ПозицияИмениТЧ + СтрДлина(ПрефиксИмениТЧ) + 1);
		Символ = Сред(ИмяОбъектаБазы, 1, 1);
	КонецЕсли;

	// состав и имена таблицы итогов по счету зависит от количества субконто,
	// поэтому добавляем еще 1 цифру
	Если ПрефиксОбъекта = "AccRgAT" Тогда
		ПрефиксОбъекта = ПрефиксОбъекта + Символ;
		ИмяОбъектаБазы = Сред(ИмяОбъектаБазы, 2);
		Символ = Сред(ИмяОбъектаБазы, 1, 1);
	КонецЕсли;

	ОписаниеОбъектаБазы.Префикс = ПрефиксОбъекта;

	ИндексОбъекта = ПрочитатьОднотипныеСимволы(ИмяОбъектаБазы);
	ИмяОбъектаБазы = Сред(ИмяОбъектаБазы, СтрДлина(ИндексОбъекта) + 1);
	Символ = Сред(ИмяОбъектаБазы, 1, 1);

	Если ЗначениеЗаполнено(ИндексОбъекта) Тогда
		ОписаниеОбъектаБазы.Индекс = Число(ИндексОбъекта);
	КонецЕсли;

	ОписаниеОбъектаБазы.Имя = СтрШаблон("%1%2",
	                                    ОписаниеОбъектаБазы.Префикс,
	                                    ОписаниеОбъектаБазы.Индекс);

	Если ЗначениеЗаполнено(Символ) Тогда
		ОписаниеОбъектаБазы.Суффикс = ИмяОбъектаБазы;
	КонецЕсли;

	ЗаполнитьЗначенияСвойств(ОписаниеОбъектаБазы, НазначениеОбъектаБазы(ОписаниеОбъектаБазы));

	Возврат ОписаниеОбъектаБазы;

КонецФункции // ОписаниеОбъектаБазыПоИмени()

// Функция - подготавливает описание объекта базы по описанию соответствия имени объекта базы и UUID
//
// Параметры:
//   СоответствиеИмениОбъектаИИд    - Структура       - описание соответствия имени объекта базы и UUID
//   ТабличныеЧасти                 - Соответствие    - описания табличных частей
//   Колонки                        - Строка          - описания колонок
// 
// Возвращаемое значение:
//  Структура    - имя объекта базы, префикс, индекс, владелец и суффикс (см. СтруктураОписанияОбъектаБазы())
//
Функция ОписаниеОбъектаБазыПоСоответствиюИмениОбъектаИИд(СоответствиеИмениОбъектаИИд,
	                                                     ТабличныеЧасти = Неопределено,
	                                                     Колонки = Неопределено);

	Имя = СтрШаблон("%1%2", СоответствиеИмениОбъектаИИд.Префикс, Формат(СоответствиеИмениОбъектаИИд.Индекс, "ЧРГ=; ЧГ="));

	Если НЕ ТипЗнч(ТабличныеЧасти) = Тип("Соответствие") Тогда
		ТабличныеЧасти = Новый Соответствие();
	КонецЕсли;

	Если НЕ ТипЗнч(Колонки) = Тип("Соответствие") Тогда
		Колонки = Новый Соответствие();
	КонецЕсли;

	Если НазначениеОбъектаБазы(СоответствиеИмениОбъектаИИд).Назначение = "Поле" Тогда
		ОписаниеОбъектаБазы = Колонки[Имя];
		Если ОписаниеОбъектаБазы = Неопределено Тогда
			Возврат Неопределено;
		КонецЕсли;
	ИначеЕсли ТабличныеЧасти[Имя] = Неопределено Тогда
		ОписаниеОбъектаБазы = ОписаниеОбъектаБазыПоИмени(Имя);
	Иначе
		ОписаниеОбъектаБазы = ТабличныеЧасти[Имя];
	КонецЕсли;

	ОписаниеОбъектаБазы.Ид = СоответствиеИмениОбъектаИИд.Ид;

	Возврат ОписаниеОбъектаБазы;

КонецФункции // ОписаниеОбъектаБазыПоСоответствиюИмениОбъектаИИд()

// Функция - подготавливает описание объекта базы по описанию соответствия имени объекта базы и UUID
//
// Параметры:
//   ОписаниеОбъектаБазы                  - Структура       - описание метаданных 1С объекта базы
//   ОписанияМетаданных                   - Соответствие    - соответствия имен таблиц СУБД и полных имен метаданных 1С
//                                                            описаниям объектов метаданных 1С
//   ИменаТаблицОбъектовКонфигурации1С    - Соответствие    - соответствия UUID объектов метаданных
//                                                            конфигурации 1С именам объектов СУБД
//   СоответствиеИменМетаданных           - Соответствие    - соответствия UUID метаданных и имен метаданных
//
// Возвращаемое значение:
//   Структура    - описание корневого владельца объекта базы
//
Функция ЗаполнитьОписаниеОбъектаБазыИВладельцев(ОписаниеОбъектаБазы,
	                                            ОписанияМетаданных,
	                                            ИменаТаблицОбъектовКонфигурации1С,
	                                            СоответствиеИменМетаданных);

	Если НЕ ОписанияМетаданных[ОписаниеОбъектаБазы.Имя] = Неопределено
		ИЛИ ОписаниеОбъектаБазы = Неопределено Тогда
		Возврат Неопределено;
	КонецЕсли;

	ОписаниеВладельца = ОписаниеОбъектаБазы;
	Пока ЗначениеЗаполнено(ОписаниеВладельца.Владелец) Цикл
		ОписаниеВладельца.Ид = ИменаТаблицОбъектовКонфигурации1С[ОписаниеВладельца.Имя].Ид;
		ОписанияМетаданных.Вставить(ОписаниеВладельца.Имя, ОписаниеВладельца);
		Если НазначениеОбъектаБазы(ОписаниеВладельца).Подчиненный Тогда
			ИмяОбъектаБазы = СтрШаблон("%1_%2", ОписаниеВладельца.Владелец.Имя, ОписаниеВладельца.Имя);
			ОписанияМетаданных.Вставить(ИмяОбъектаБазы, ОписаниеВладельца);
		КонецЕсли;
		ОписаниеВладельца = ОписаниеВладельца.Владелец;
	КонецЦикла;
	
	Если ИменаТаблицОбъектовКонфигурации1С[ОписаниеВладельца.Имя] = Неопределено Тогда
		Возврат Неопределено;
	КонецЕсли;
	
	ОписаниеВладельца.Ид = ИменаТаблицОбъектовКонфигурации1С[ОписаниеВладельца.Имя].Ид;
	
	Если НЕ СоответствиеИменМетаданных[ОписаниеВладельца.Ид] = Неопределено Тогда
		ОписаниеВладельца.ИмяМетаданных = СоответствиеИменМетаданных[ОписаниеВладельца.Ид].ИмяМетаданных;
	КонецЕсли;

	ОписанияМетаданных.Вставить(ОписаниеВладельца.Имя, ОписаниеВладельца);

	ТекОписание = ОписаниеОбъектаБазы;
	Пока ЗначениеЗаполнено(ТекОписание.Владелец) Цикл
		ТекОписание.ИмяМетаданных =
			ИмяМетаданных(СоответствиеИменМетаданных[ОписаниеВладельца.Ид].Данные, ТекОписание);
		ТекОписание = ТекОписание.Владелец;
	КонецЦикла;

	ЗаполнитьПолныеИменаМетаданныхВОписанииОбъектаБазы(ОписаниеОбъектаБазы);

	Возврат ОписаниеВладельца;

КонецФункции // ЗаполнитьОписаниеОбъектаБазыИВладельцев()

// Функция - собирает полное имя объекта метаданных по описанию с учетом всех владельцев
// например (Справочник.Справочник1.Реквизит1, Документ.ТабличнаяЧасть2.Реквизит8)
//
// Параметры:
//   ОписаниеОбъектаБазы    - Структура    - описание объекта метаданных (см. ОписаниеОбъектаБазыПоИмени())
//
// Возвращаемое значение:
//   Строка    - полное имя объекта метаданных
//
Функция ПолноеИмяОбъектаМетаданных(Знач ОписаниеОбъектаБазы)

	Если НЕ ЗначениеЗаполнено(ОписаниеОбъектаБазы.ИмяМетаданных) Тогда
		Возврат "";
	КонецЕсли;

	ТекОписание = ОписаниеОбъектаБазы;

	ПолноеИмя = ТекОписание.ИмяМетаданных;

	Пока ЗначениеЗаполнено(ТекОписание.Владелец) Цикл
		ПолноеИмя = СтрШаблон("%1.%2", ТекОписание.Владелец.ИмяМетаданных, ПолноеИмя);
		ТекОписание = ТекОписание.Владелец;
	КонецЦикла;

	Возврат СтрШаблон("%1.%2", ТекОписание.Тип, ПолноеИмя);

КонецФункции // ПолноеИмяОбъектаМетаданных()

// Процедура - заполняет полные имена метаданных в описании объекта базы и его владельцах
//
// Параметры:
//   ОписаниеОбъектаБазы    - Структура    - описание объекта метаданных (см. ОписаниеОбъектаБазыПоИмени())
//
Процедура ЗаполнитьПолныеИменаМетаданныхВОписанииОбъектаБазы(ОписаниеОбъектаБазы)

	ТекОписание = ОписаниеОбъектаБазы;

	Пока ЗначениеЗаполнено(ТекОписание) Цикл
		ТекОписание.Вставить("ПолноеИмяМетаданных", ПолноеИмяОбъектаМетаданных(ТекОписание));
		ТекОписание = ТекОписание.Владелец;
	КонецЦикла;

КонецПроцедуры // ЗаполнитьПолныеИменаМетаданныхВОписанииОбъектаБазы()

// Функция - находит в тестовом описании объекта метаданных его имя
// для отдельных типов объектов возвращает стандартное имя
//
// Параметры:
//   ТекстОписания               - Строка                - описание объекта метаданных (скобкотекст)
//   ИдИлиОписаниеОбъектаБазы    - Структура, Строка     - UUID объекта метаданных
//
// Возвращаемое значение:
//   Строка    - имя объекта метаданных
//
Функция ИмяМетаданных(ТекстОписания, ИдИлиОписаниеОбъектаБазы)

	ИмяМетаданных = "";

	Если ТипЗнч(ИдИлиОписаниеОбъектаБазы) = Тип("Структура") Тогда
		Ид = "";
		Если ИдИлиОписаниеОбъектаБазы.Тип = "НомерСтроки" Тогда
			ИмяМетаданных = "НомерСтроки";
		ИначеЕсли ИдИлиОписаниеОбъектаБазы.Тип = "Ссылка" Тогда
			ИмяМетаданных = "Ссылка";
		Иначе
			Ид = ИдИлиОписаниеОбъектаБазы.Ид;
		КонецЕсли;
	Иначе
		Ид = ИдИлиОписаниеОбъектаБазы;
	КонецЕсли;

	Если НЕ ЗначениеЗаполнено(Ид) Тогда
		Возврат ИмяМетаданных;
	КонецЕсли;

	РВ = Новый РегулярноеВыражение(СтрШаблон("%1},""([_a-zA-Zа-яА-ЯёЁ\d]+)""", Ид));

	Совпадения = РВ.НайтиСовпадения(ТекстОписания);

	Если Совпадения.Количество() = 0 Тогда
		ИмяМетаданных = "";
	Иначе
		ИмяМетаданных = Совпадения[0].Группы[1].Значение;
	КонецЕсли;

	Возврат ИмяМетаданных;

КонецФункции // ИмяМетаданных()

// Функция - находит в текстовом описании (скобочнике) информацию о конфигурации, авторе и т.п. и добавляет в описание
//
// Параметры:
//   ОписаниеКонфигурации    - Структура    - структура описания конфигурации
//   ТекстОписания           - Строка       - текстовое описание конфигурации (скобочник)
//
Процедура ЗаполнитьТекстыВОписанииКонфигурации(ОписаниеКонфигурации, ТекстОписания)

	РВ_Имя = Новый РегулярноеВыражение("^\{\d+,\d+," +
	                                   "(?i)(?:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\},""(.+)"",");

	РВ_Текст = Новый РегулярноеВыражение("^\{0\}|^\{\d+,"".*?"",""((?:.|\s)+?)""\}");

	Совпадения = РВ_Имя.НайтиСовпадения(ТекстОписания);

	Если Совпадения.Количество() > 0 Тогда
		ОписаниеКонфигурации.Имя = Совпадения[0].Группы[1].Значение;
	КонецЕсли;

	Синоним_Индекс                      = 0;
	ПодробнаяИнформация_Индекс          = 1;
	КраткаяИнформация_Индекс            = 2;
	АвторскиеПрава_Индекс               = 3;
	АдресИнформацииОПоставщике_Индекс   = 4;
	АдресИнформацииОКонфигурации_Индекс = 5;

	Совпадения = РВ_Текст.НайтиСовпадения(ТекстОписания);

	Если Совпадения.Количество() > 0 Тогда
		ПустоеЗначение = "{0}";
		ОписаниеКонфигурации.Синоним =
			?(Совпадения[Синоним_Индекс].Значение = ПустоеЗначение,
			  "",
			  Совпадения[Синоним_Индекс].Группы[1].Значение);
		ОписаниеКонфигурации.ПодробнаяИнформация =
			?(Совпадения[ПодробнаяИнформация_Индекс].Значение = ПустоеЗначение,
			  "",
			  Совпадения[ПодробнаяИнформация_Индекс].Группы[1].Значение);
		ОписаниеКонфигурации.КраткаяИнформация =
			?(Совпадения[КраткаяИнформация_Индекс].Значение = ПустоеЗначение,
			  "",
			  Совпадения[КраткаяИнформация_Индекс].Группы[1].Значение);
		ОписаниеКонфигурации.АвторскиеПрава =
			?(Совпадения[АвторскиеПрава_Индекс].Значение = ПустоеЗначение,
			  "",
			  Совпадения[АвторскиеПрава_Индекс].Группы[1].Значение);
		ОписаниеКонфигурации.АдресИнформацииОПоставщике =
			?(Совпадения[АдресИнформацииОПоставщике_Индекс].Значение = ПустоеЗначение,
			  "",
			  Совпадения[АдресИнформацииОПоставщике_Индекс].Группы[1].Значение);
		ОписаниеКонфигурации.АдресИнформацииОКонфигурации =
			?(Совпадения[АдресИнформацииОКонфигурации_Индекс].Значение = ПустоеЗначение,
			  "",
			  Совпадения[АдресИнформацииОКонфигурации_Индекс].Группы[1].Значение);
	КонецЕсли;

КонецПроцедуры // ЗаполнитьТекстыВОписанииКонфигурации()

// Функция - находит в текстовом описании (скобочнике) информацию о версии конфигурации и добавляет в описание
//
// Параметры:
//   ОписаниеКонфигурации    - Структура    - структура описания конфигурации
//   ТекстОписания           - Строка       - текстовое описание конфигурации (скобочник)
//
Процедура ЗаполнитьВерсиюВОписанииКонфигурации(ОписаниеКонфигурации, ТекстОписания)

	РВ_Версия = Новый РегулярноеВыражение("^(?:\{0\}|\{\d+,"".*"","".*""\})," +
	                                      "(?:(?i)(?:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}),){4}" +
	                                      "\d+,""(.*)"",""(.*)"",""(.*)"",");
	РВ_РежимСовместимости =
		Новый РегулярноеВыражение("^\{?\d+,\d+\},\d+," +
	                              "(?:(?i)(?:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}),){4}(\d+)");

	Поставщик_Индекс               = 1;
	Версия_Индекс                  = 2;
	АдресКаталогаОбновлений_Индекс = 3;

	Совпадения = РВ_Версия.НайтиСовпадения(ТекстОписания);

	Если Совпадения.Количество() > 0 Тогда
		ОписаниеКонфигурации.Поставщик               = Совпадения[0].Группы[Поставщик_Индекс].Значение;
		ОписаниеКонфигурации.Версия                  = Совпадения[0].Группы[Версия_Индекс].Значение;
		ОписаниеКонфигурации.АдресКаталогаОбновлений = Совпадения[0].Группы[АдресКаталогаОбновлений_Индекс].Значение;
	КонецЕсли;

	Совпадения = РВ_РежимСовместимости.НайтиСовпадения(ТекстОписания);

	Если Совпадения.Количество() > 0 Тогда
		ОписаниеКонфигурации.РежимСовместимости = Совпадения[0].Группы[1].Значение;
	КонецЕсли;

КонецПроцедуры // ЗаполнитьВерсиюВОписанииКонфигурации()

// Функция - распаковыает переданные данные, упакованные по алгоритму deflate
//
// Параметры:
//   УпакованныеДанные    - Строка, ДвоичныеДАнные    - данные для распаковки
//   КакТекст             - Булево                    - Истина - результат будет возвращет в виде строки
//                                                      Ложь - результат будет возвращет в виде двоичных данных
//
// Возвращаемое значение:
//    Строка, ДвоичныеДанные    - распакованные данные
//
Функция ПрочитатьУпакованныеДанные(УпакованныеДанные, КакТекст = Ложь)

	ТипУпакованныхДанных = ТипЗнч(УпакованныеДанные);
	Если ТипУпакованныхДанных = Тип("ДвоичныеДанные") Тогда
		Данные = УпакованныеДанные;
	ИначеЕсли ТипУпакованныхДанных = Тип("Строка") Тогда
		Данные = Base64Значение(УпакованныеДанные);
	Иначе
		ВызватьИсключение СтрШаблон("Некорректный тип параметра ""УпакованныеДанные"" ""%1"",
		                            | ожидается ""ДвоичныеДанные"" или ""Строка""",
		                            ТипУпакованныхДанных);
	КонецЕсли;

	Если ДанныеУпакованы(Данные) Тогда
		Упаковщик = Новый УпаковщикDeflate();
		Данные = Упаковщик.РаспаковатьДанные(Данные);
	Иначе
		Лог.Отладка("Данные ""%1"" не упакованы", УпакованныеДанные);
	КонецЕсли;

	Если КакТекст Тогда
		Чтение = Новый ЧтениеТекста(Данные.ОткрытьПотокДляЧтения(), КодировкаТекста.UTF8);
		Данные = Чтение.Прочитать();
	КонецЕсли;

	Возврат Данные;

КонецФункции // ПрочитатьУпакованныеДанные()

// Функция - проверяет, что данные упакованы по алгоритму deflate
// если в начале данных расположен BOM (0xEF (239), 0xBB (187), 0xBF (191)) - данные не упакованы
//
// Параметры:
//  Данные     - Строка, ДвоичныеДанные    - проверяемые данные
// 
// Возвращаемое значение:
//  Булево    - Истина - данные упакованы по алгоритму deflate
//
Функция ДанныеУпакованы(Знач Данные)

	ТипДанных = ТипЗнч(Данные);
	ЭтоПоток = (ТипДанных = Тип("Поток")
	       ИЛИ ТипДанных = Тип("ФайловыйПоток")
	       ИЛИ ТипДанных = Тип("ПотокВПамяти"));

	Если ТипДанных = Тип("ДвоичныеДанные") Тогда
		Поток = Данные.ОткрытьПотокДляЧтения();
	ИначеЕсли ТипДанных = Тип("Строка") Тогда
		Данные = Base64Значение(Данные);
		Поток = Данные.ОткрытьПотокДляЧтения();
	ИначеЕсли ЭтоПоток Тогда
		Данные.СкопироватьВ(Поток);
	Иначе
		ВызватьИсключение СтрШаблон("Некорректный тип ""%1"" параметра ""Данные"",
		                            | ожидается ""Base64Строка, Поток, ДвоичныеДанные""",
		                            ТипДанных);
	КонецЕсли;

	ДлинаБОМ = 3;
	КодСимволаБОМ1 = 239; // 0xEF
	КодСимволаБОМ2 = 187; // 0xBB
	КодСимволаБОМ3 = 191; // 0xBF

	Поток.Перейти(0, ПозицияВПотоке.Начало);

	Буфер = Новый БуферДвоичныхДанных(ДлинаБОМ);

	Поток.Прочитать(Буфер, 0, ДлинаБОМ);

	Возврат НЕ (Буфер[0] = КодСимволаБОМ1 И Буфер[1] = КодСимволаБОМ2 И Буфер[2] = КодСимволаБОМ3);

КонецФункции // ДанныеУпакованы()

// Функция - убирает из строки начальные и конечные кавычки
// если строка содержит только цифры, то преобразует в число
//
// Параметры:
//   Строка    - Строка     - исходная строка
//
// Возвращаемое значение:
//   Строка, Число    - результат приведения
//
Функция ПривестиСтроку(Знач Строка)

	Результат = СокрЛП(Строка);

	УдалитьСимволов = 2;

	Если Лев(Результат, 1) = """" И Прав(Результат, 1) = """" Тогда
		Результат = Сред(Результат, УдалитьСимволов, СтрДлина(Результат) - УдалитьСимволов);
	КонецЕсли;

	Если ПустаяСтрока(Результат) Тогда
		Возврат Результат;
	КонецЕсли;

	Если ЭтоЧисло(Результат) Тогда
		Результат = Число(Результат);
	КонецЕсли;

	Возврат Результат;

КонецФункции // ПривестиСтроку()

// Процедура - удаляет лидирующий символ "_" из имени объекта
//
// Параметры:
//  Имя      - Строка    - имя объекта
//
Процедура УбратьЛидирующееПодчеркивание(Имя)

	НачальнаяПозиция = 2;

	Если Лев(Имя, 1) = "_" Тогда
		Имя = Сред(Имя, НачальнаяПозиция);
	КонецЕсли;

КонецПроцедуры // УбратьЛидирующееПодчеркивание()

// Функция - возвращает часть строки до первого символа "тип" которого отличается от прочитанных
// т.е. читает все цифры до первого нецифрового символа либо все нецифровые символы до первой цифры
//
// Параметры:
//   ИсходнаяСтрока    - Строка     - исходная строка
//
// Возвращаемое значение:
//   Строка    - Истина - строка не пустая и содержит только цифры
//
Функция ПрочитатьОднотипныеСимволы(Знач ИсходнаяСтрока)

	Если НЕ ЗначениеЗаполнено(ИсходнаяСтрока) Тогда
		Возврат "";
	КонецЕсли;

	Совпадения = ВыражениеОднотипныхСимволов.НайтиСовпадения(ИсходнаяСтрока);

	Если Совпадения.Количество() = 0 Тогда
		ПрочитанныеСимволы = "";
	Иначе
		ПрочитанныеСимволы = Совпадения[0].Группы[0].Значение;
	КонецЕсли;

	Возврат ПрочитанныеСимволы;

КонецФункции // ПрочитатьОднотипныеСимволы()

// Функция - проверяет, что строка не пустая и содержит только цифры
//
// Параметры:
//   Строка    - Строка     - исходная строка
//
// Возвращаемое значение:
//   Булево    - Истина - строка не пустая и содержит только цифры
//
Функция ЭтоЧисло(Строка)

	Если НЕ ЗначениеЗаполнено(Строка) Тогда
		Возврат Ложь;
	КонецЕсли;

	Возврат ВыражениеПроверкиЧисла.Совпадает(Строка);

КонецФункции // ЭтоЧисло()

#КонецОбласти // СлужебныеПроцедурыИФункции

#Область ОбработчикиСобытий

// Процедура - обработчик события "ПриСозданииОбъекта"
//
// Параметры:
//    _ПодключениеКСУБД    - ПодключениеКСУБД    - объект подключения к СУБД
//    _База                - Строка              - имя базы данных
//
// BSLLS:UnusedLocalMethod-off
Процедура ПриСозданииОбъекта(Знач _ПодключениеКСУБД, _База)

	ПодключениеКСУБД = _ПодключениеКСУБД;
	ТекущийСервер    = ПодключениеКСУБД.Сервер();
	База             = _База;

	ЗаполнитьНазначенияОбъектовБазы();

	ВыражениеПроверкиЧисла = Новый РегулярноеВыражение("^\d+$|^\d+.\d+$");
	ВыражениеОднотипныхСимволов = Новый РегулярноеВыражение("^\d+|^[a-zAZ]+");

	Лог = ПараметрыСистемы.Лог();

КонецПроцедуры // ПриСозданииОбъекта()
// BSLLS:UnusedLocalMethod-on

#КонецОбласти // ОбработчикиСобытий
